home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / Utils / Brian's Extensions / SWTranslucentBlitters.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  42.8 KB  |  1,238 lines  |  [TEXT/CWIE]

  1. /*  -----------------------------------------------------------------------------------
  2.     -----------------------------------------------------------------------------------
  3.     SWTranslucentBlitters.c
  4.     
  5.     by Brian Roddy
  6.     
  7.     4/13/97
  8.  
  9.     Routines for blitting translucent sprites in 8 bit or in 16 bit mode.  Both versions
  10.     require a lookup table to work properly.  These lookup tables need to be initialized
  11.     before being used.  To initialize the 16 bit version, call 
  12.  
  13.     err = SWCreate16BitTranslucencyTable();
  14.  
  15.     This creates a table which supports 30 levels of translucency and is small.  The 8-bit 
  16.     table is much bigger.  It requires 256 * 256 bytes (or 64K) of memory for each level
  17.     of translucency.  It also takes a relatively long time to compute.  For this reason
  18.     we have a number of functions to allow creating these tables in advance and saving them
  19.     in the resource fork so they can be loaded quickly.  By default you can call:
  20.  
  21.     err = SWLoadOrCreate8BitTranslucencyTable(numLevelsOfTranslucency);
  22.  
  23.     This single purpose function will try and load the table from a resource.  If it
  24.     does not exist, it will create the table and save it to the resource fork before continuing.
  25.     This means that the first time you run the program, it will be slow and will compute
  26.     this and save it.  Next time you run the program it can just load it and thus will
  27.     start up quickly.  Note that you can go into ResEdit and copy a TTAB resource that
  28.     has been computed and paste it into your project's resource file.  This way, it will 
  29.     automatically be copied into your application's resource fork at link timeand therefore 
  30.     will never have to be computed.  (To reiterate, you run your program first. This 
  31.     generates the computed table and stores it in the TTAB resource.  You copy this resource 
  32.     into your project's resource file.  From then on this TTAB will get copied to your 
  33.     application so you won't have to wait for it to be computed each time you recompile 
  34.     and run.)
  35.     
  36.     More detailed functions for manipulating these tables exist.  See the source code
  37.     for more details in the comments.
  38.  
  39.  
  40.     Once you've called initialized the table or tables, you can set a Sprite's translucency
  41.     level with:
  42.  
  43.     SWSetSpriteTranslucencyLevel(mySpritePtr, 6)
  44.     
  45.     where mySpritePtr is a SpritePtr and 6 is a byte specifying the translucency level.
  46.     This level is a number from 1 to the number of Levels, where 1 is barely
  47.     visible and a higher number is more opaque.  If a level of any other value (e.g. 0
  48.     or >= number of levels)    is specified, the Sprite is considered fully opaque and is 
  49.     thus blitted normally.
  50.     
  51.     You can find a sprite's level of translucency with 
  52.     
  53.     SWGetSpriteTranslucencyLevel(mySpritePtr)
  54.  
  55.     which will return the level as a byte, or 0 if the sprite is opaque.
  56.     
  57.     IMPORTANT: The translucent blitters and idle Sprites do not mix! This means that each
  58.     translucent Sprite should have a MoveProc or FrameProc that is called every frame that
  59.     sets the Sprite's needsToBeDrawn flag to true.
  60.  
  61.  
  62.     -----------------------------------------------------------------------------------
  63.     Implementation Notes:
  64.  
  65.     The 8-bit blitter is fairly optimal.  There is some inline assembly to create four
  66.     pixel longs in a minimal number of operations.  Note that as the processor is much
  67.     faster than the bus, we spend a couple extra cycles to create this long so all
  68.     four can be passed at once.
  69.  
  70.     The 16-bit blitter is extremely optimized.  The bulk is written in assembly and uses
  71.     a lookup table.
  72.  
  73.     N.B.: Blitters are modified versions of blitters from SpriteWorld 2
  74.  
  75.     This source code is available for free use.
  76.     ----------------------------------------------------------------------------------- 
  77.     ----------------------------------------------------------------------------------- */
  78.  
  79. #include <Resources.h>
  80.  
  81. #include <SWTranslucentBlitters.h>
  82.  
  83.  
  84. #pragma mark -----Public API-----
  85. ///--------------------------------------------------------------------------------------
  86. //    Setting and Getting translucency level
  87. ///--------------------------------------------------------------------------------------
  88.  
  89. SW_FUNC OSErr SWSetSpriteTranslucencyLevel(
  90.     SpritePtr srcSpriteP,
  91.     unsigned long level) 
  92. {
  93.     short         currentPixelDepth;
  94.     OSErr        err;
  95.     
  96.     
  97.     currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
  98.     err = kWrongDepthErr;
  99.     
  100.     srcSpriteP->translucencyLevel = level;
  101.     
  102.     if (currentPixelDepth == 8)
  103.     {
  104.         if ((level <= 0) || (level > gNumberOf8BitTranslucencyLevels)) {
  105.             srcSpriteP->frameDrawProc = BlitPixieMaskDrawProc;
  106.         } else {
  107.             srcSpriteP->translucencyLevel--;
  108.             // preshift it 
  109.             srcSpriteP->translucencyLevel <<= 16;
  110.             srcSpriteP->frameDrawProc = BlitPixie8BitTranslucentMaskDrawProc;
  111.         }
  112.         err = noErr;
  113.     }
  114.     else if (currentPixelDepth == 16)
  115.     {
  116.         if ((level <= 0) || (level >= kNumberOf16BitTranslucencyLevels)) {
  117.             srcSpriteP->frameDrawProc = BlitPixieMaskDrawProc;
  118.         } else {
  119.             srcSpriteP->frameDrawProc = BlitPixie16BitTranslucentMaskDrawProc;
  120.         }
  121.         err = noErr;
  122.     }
  123.     SWSetStickyIfError( err );
  124.     return err;
  125. }
  126.  
  127.  
  128. SW_FUNC unsigned long SWGetSpriteTranslucencyLevel(SpritePtr srcSpriteP) {
  129.     short         currentPixelDepth;
  130.     currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
  131.     if (currentPixelDepth == 8)
  132.         if (srcSpriteP->frameDrawProc == BlitPixie8BitTranslucentMaskDrawProc)
  133.             return ((srcSpriteP->translucencyLevel) >> 16) + 1;
  134.         else 
  135.             return 0;
  136.     else if (currentPixelDepth == 16)
  137.         if (srcSpriteP->frameDrawProc == BlitPixie16BitTranslucentMaskDrawProc)
  138.             return srcSpriteP->translucencyLevel;
  139.         else 
  140.             return 0;
  141.     else
  142.         return 0;
  143. }
  144.  
  145.  
  146. ///--------------------------------------------------------------------------------------
  147. ///--------------------------------------------------------------------------------------
  148. ///--------------------------------------------------------------------------------------
  149. /// 8-Bit Routines
  150. ///--------------------------------------------------------------------------------------
  151. ///--------------------------------------------------------------------------------------
  152. ///--------------------------------------------------------------------------------------
  153.  
  154. #pragma mark -----8 Bit Table Management-----
  155.  
  156. //-----------------------------------------------------------------------------
  157. // 8-bit Translucency Table Management
  158. //-----------------------------------------------------------------------------
  159.  
  160. // The Lookup table which is indexed by a [translucencyLevel][sourceColor][translucentColor]
  161. // Note that all colors are 8-bit, so this thing is 64K * gNumberOf8BitTranslucencyLevels
  162. // For instance, 8 levels adds up to half a meg.
  163. unsigned char *g8BitTranslucencyTable = NULL;
  164.  
  165. // Our array for storing the current CLUT in an easily accessible fashion.
  166. RGBColor     kSystemColorArray[kNumberOfColors];
  167.  
  168. // Number of Levels we currently support
  169. int gNumberOf8BitTranslucencyLevels = 0;
  170.  
  171.  
  172. ///--------------------------------------------------------------------------------------
  173. // -- SWLoadOrCreate8BitTranslucencyTable --
  174. ///--------------------------------------------------------------------------------------
  175. // This function may be called to get the translucency table in memory.
  176. // It either loads a premade table from the resource fork of the app,
  177. // or if it does not exist.  calculates the table and saves it in the resource fork.
  178. // Note that each table is CLUT specific.  Therefore, set the CLUT
  179. // before calling this.
  180. // To save development time, after this calculates and saves the table into the
  181. // TTAB resource of your application, go into resedit and copy the TTAB resource 
  182. // from the application and paste it into your project's resource file.  This way
  183. // the resource will get added to your application at link time and you won't have  
  184. // to wait for it to recompute each time.
  185.  
  186. OSErr     SWLoadOrCreate8BitTranslucencyTable (int numberOfLevels) {
  187.     OSErr                tableAllocationErr = noErr;
  188.     OSErr                err = noErr;
  189.  
  190.     // Ignore if we've already done this.
  191.     if (g8BitTranslucencyTable == NULL) {
  192.     
  193.         // First try loading the table from the resource fork.
  194.         // Note we hard code it being in resource ID 128.  If you want
  195.         // to support multiple CLUTS, you can create multiple tables
  196.         // and store them under different resource IDs and load them
  197.         // when you load your CLUT.  You of course have to precompute 
  198.         // these tables
  199.         
  200.         err = SWLoad8BitTranslucencyTable(128);
  201.         
  202.         // If there is an error or the number of levels doesn't match up,
  203.         // then we have to compute it (which can take a little while)
  204.         if ((err != noErr) || (numberOfLevels != gNumberOf8BitTranslucencyLevels)) {
  205.             err = SWCreate8BitTranslucencyTable(numberOfLevels);
  206.             
  207.             // And save it when we're done
  208.             if (err == noErr) {
  209.                 err = SWSave8BitTranslucencyTable(128);
  210.             }
  211.         }
  212.     }
  213.     return err;
  214. }
  215.  
  216. ///--------------------------------------------------------------------------------------
  217. //  -- SWDispose8BitTranslucencyTable --
  218. ///--------------------------------------------------------------------------------------
  219. // This function must be called to clear the table from memory.
  220.  
  221. void     SWDispose8BitTranslucencyTable(void)
  222. {
  223.     // Only do this if we've created a table.
  224.     if (g8BitTranslucencyTable != NULL)
  225.     {
  226.         DisposePtr((Ptr)g8BitTranslucencyTable);
  227.         g8BitTranslucencyTable = NULL;
  228.         gNumberOf8BitTranslucencyLevels = 0;
  229.     }
  230. }
  231.  
  232. ///--------------------------------------------------------------------------------------
  233. //  -- SWCreate8BitTranslucencyTable --
  234. ///--------------------------------------------------------------------------------------
  235. // This function will allocate and compute a table with the specified number of levels.
  236.  
  237.  
  238. OSErr     SWCreate8BitTranslucencyTable (int numberOfLevels) {
  239.     OSErr                tableAllocationErr = noErr;
  240.     unsigned long        arraySize;
  241.  
  242.     // If we've already done this, get rid of the old one
  243.     if (g8BitTranslucencyTable != NULL) SWDispose8BitTranslucencyTable();
  244.     
  245.     // First we need to allocate the array.
  246.     arraySize = numberOfLevels * 65536 * sizeof(unsigned char);
  247.     g8BitTranslucencyTable = (unsigned char *)NewPtr(arraySize);
  248.     tableAllocationErr = MemError();
  249.  
  250.     // If we were able to then we continue loading or creating
  251.     // the table.
  252.     if (tableAllocationErr == noErr) {
  253.         // Store our number of levels
  254.         gNumberOf8BitTranslucencyLevels = numberOfLevels;
  255.         
  256.         // so we load up the CLUT into an array so we have fast access to it.
  257.         CreateCLUTTable();
  258.         // We compute the table (albeit slowly)
  259.         Calc8BitTranslucencyTable(numberOfLevels);
  260.     }
  261.  
  262.     return tableAllocationErr;
  263. }
  264.  
  265.  
  266. ///--------------------------------------------------------------------------------------
  267. //    SWLoad8BitTranslucencyTable
  268. ///--------------------------------------------------------------------------------------
  269. // This function will load the translucency table from a TTAB resource of the specified ID,
  270. // rather than recomputing it from scratch each time.  Note that the first byte in the 
  271. // resource specifies the number of levels of translucency.
  272.  
  273. OSErr SWLoad8BitTranslucencyTable(short resourceID) {
  274.     unsigned char        **TranslucencyTableHandle;
  275.     unsigned char        *TranslucencyTableData;
  276.     OSErr                err = noErr;
  277.     unsigned long         arraySize;
  278.     
  279.     // If we've already done this, get rid of the old one
  280.     if (g8BitTranslucencyTable != NULL) SWDispose8BitTranslucencyTable();
  281.  
  282.     // Try and get a handle on the stored table
  283.     TranslucencyTableHandle = (unsigned char **)Get1Resource('TTAB', resourceID);
  284.     if (TranslucencyTableHandle == NULL)
  285.     {
  286.         err = ResError();
  287.         if (err == noErr)
  288.             err = resNotFound;
  289.     }
  290.     
  291.     // If it's there then we copy it into our Array.
  292.     if (err == noErr) {    
  293.         HLock((Handle)TranslucencyTableHandle);
  294.         TranslucencyTableData = *TranslucencyTableHandle;
  295.         
  296.         // First store the number of translucency levels
  297.         gNumberOf8BitTranslucencyLevels = *TranslucencyTableData++;
  298.  
  299.         // then create a new translucency table
  300.         arraySize = gNumberOf8BitTranslucencyLevels * 65536 * sizeof(unsigned char);
  301.         g8BitTranslucencyTable = (unsigned char *)NewPtr(arraySize);
  302.         err = MemError();
  303.  
  304.         if (err == noErr) {
  305.         // and copy the data into the translucency table array
  306.             BlockMove(TranslucencyTableData,
  307.                       g8BitTranslucencyTable, 
  308.                       arraySize);
  309.         } else {
  310.             gNumberOf8BitTranslucencyLevels = 0;
  311.             g8BitTranslucencyTable = NULL;
  312.         }
  313.         HUnlock((Handle)TranslucencyTableHandle);
  314.     }
  315.  
  316.     
  317.     // Then we free up our loaded table, because we've copied it to our array.
  318.     if (TranslucencyTableHandle != NULL) {
  319.         ReleaseResource((Handle)TranslucencyTableHandle);
  320.     }
  321.         // SWStickyErr not set, because an error might be expected, and mean 
  322.         // the TTAB has to be calculated
  323.     return err;
  324. }
  325.  
  326.  
  327. ///--------------------------------------------------------------------------------------
  328. //    SWSave8BitTranslucencyTable
  329. ///--------------------------------------------------------------------------------------
  330. // This function will save the translucency table from a TTAB resource of the specified ID,
  331. // so it can be loaded later.  The format of the table is: the first byte is the number 
  332. // of levels of translucency, the subsequent bytes are the table.
  333.  
  334. OSErr SWSave8BitTranslucencyTable(short resourceID) {
  335.     Boolean        createdNewResource;
  336.     OSErr        err = noErr;
  337.     unsigned long arraySize;
  338.     unsigned char        **TranslucencyTableHandle;
  339.     unsigned char        *TranslucencyTableData;
  340.     
  341.     // Make sure there is a Translucency Table to save
  342.     if (g8BitTranslucencyTable == NULL) 
  343.         err = kNullTileMapErr;
  344.         
  345.     // Load or create the resource
  346.     if (err == noErr) {
  347.         arraySize = gNumberOf8BitTranslucencyLevels * 65536 * sizeof(unsigned char);
  348.  
  349.         // Check if the resource already exisits
  350.         TranslucencyTableHandle = (unsigned char **)Get1Resource('TTAB', resourceID);
  351.         
  352.         // If it already exists
  353.         if (TranslucencyTableHandle != NULL) {
  354.             SetHandleSize((Handle)TranslucencyTableHandle, arraySize + 1);
  355.             err = MemError();
  356.             // we free it up
  357.             if (err != noErr)
  358.                 ReleaseResource((Handle)TranslucencyTableHandle);
  359.             
  360.             createdNewResource = false;
  361.         }
  362.         // If it doesn't exist, we get some memory so we can create it
  363.         else if (ResError() == resNotFound || ResError() == noErr) {
  364.             TranslucencyTableHandle = (unsigned char **)NewHandle(arraySize + 1);
  365.             err = MemError();
  366.             createdNewResource = true;
  367.         }
  368.         else 
  369.             err = ResError();
  370.     }
  371.     // Copy the data into the resource handle
  372.     if (err == noErr) {    
  373.         HLock((Handle)TranslucencyTableHandle);
  374.         if (createdNewResource) {
  375.             AddResource((Handle)TranslucencyTableHandle, 'TTAB', resourceID, "\p");
  376.             err = ResError();
  377.             
  378.             HLock((Handle)TranslucencyTableHandle);
  379.             TranslucencyTableData = *TranslucencyTableHandle;
  380.             *TranslucencyTableData = (unsigned char)gNumberOf8BitTranslucencyLevels;
  381.             TranslucencyTableData++;
  382.             
  383.             // Copy the data from the translucency table array
  384.             BlockMove(g8BitTranslucencyTable,
  385.                       TranslucencyTableData, 
  386.                       arraySize);
  387.             
  388.             if (err != noErr)
  389.                 DisposeHandle((Handle)TranslucencyTableHandle);
  390.         
  391.         } else {
  392.             // If there is an error, free everthing up.
  393.             ChangedResource((Handle)TranslucencyTableHandle);
  394.             err = ResError();
  395.             
  396.             if (err != noErr)
  397.                 ReleaseResource((Handle)TranslucencyTableHandle);
  398.         }
  399.     }
  400.     // Update the resource file and clean up
  401.     if (err == noErr) {
  402.         UpdateResFile( CurResFile() );
  403.         ReleaseResource((Handle)TranslucencyTableHandle);
  404.     }
  405.     SWSetStickyIfError(err);
  406.     return err;
  407. }
  408.  
  409. // End Public Functions
  410. // ------------------------------------------------------------------------------
  411.  
  412.  
  413.  
  414.  
  415. // ------------------------------------------------------------------------------
  416. // ------------------------------------------------------------------------------
  417. // Our internal color table computation functions:
  418.  
  419. // -- ColorToIndex --
  420. // Given an RGB triplet, determine which color in the current CLUT
  421. // is closest and return the index of that color.
  422. unsigned char    ColorToIndex(long curRed, long curGreen, long curBlue) {
  423.     unsigned long j, dist, bestDist;
  424.     unsigned char bestMatch;
  425.     long rr, gg, bb;
  426.  
  427.     bestDist = 0xFFFFFFFF;
  428.     
  429.     for (j=0; j < kNumberOfColors; j++) {
  430.         rr = ABS(curRed - kSystemColorArray[j].red);
  431.         gg = ABS(curGreen - kSystemColorArray[j].green);
  432.         bb = ABS(curBlue - kSystemColorArray[j].blue);
  433.         dist = rr + gg + bb;
  434.         if (dist < bestDist) {
  435.             bestMatch = j;
  436.             bestDist = dist;
  437.         }
  438.     }
  439.     return bestMatch;
  440. }
  441.  
  442. // -- CalcNewColorValue --
  443. // Given two reds, greens or blues and a percent of translucency (from 0.0 to 1.0),
  444. // this calculates the blended version of the colors.  This is the actual work of
  445. // computing the translucent color.
  446. long     CalcNewColorValue (long sourceValue, long blendValue, float ratio) {
  447.     float newValue = (ratio * (float)sourceValue) + ((1.0 - ratio) * (float)blendValue);
  448.     return (long)newValue;
  449. }
  450.  
  451. // -- Calc8BitTranslucencyTable --
  452. // internal function that does the work.
  453. void     Calc8BitTranslucencyTable (int numberOfLevels) {
  454.     long curRed, curGreen, curBlue;
  455.     RGBColor curSourceColor, curBlendColor;
  456.     long sourceColor, blendColor;
  457.     long arrayIndex = 0;
  458.     unsigned char newIndex;
  459.     float curLevel, ratio;
  460.     // For each level of translucency
  461.     for (curLevel = 0.0; curLevel < numberOfLevels; curLevel += 1.0) {
  462.         // We calculate the current translucency percentage (between 0.0 and 1.0)
  463.         // (note we assume the user wants translucency levels evenly distributed
  464.         //  between (and not including) 0 and 1. 
  465.         ratio = ((curLevel + 1.0) / (numberOfLevels + 1.0));
  466.         // For each of our 256 possible source background colors
  467.         for (sourceColor = 0; sourceColor < kNumberOfColors; sourceColor++) {
  468.             curSourceColor = kSystemColorArray[sourceColor];
  469.             // For each of our 256 possible blended sprite colors 
  470.             for (blendColor = 0; blendColor < kNumberOfColors; blendColor++) {
  471.                 curBlendColor = kSystemColorArray[blendColor];
  472.                 // Calculate the value of the blended R, G, and B
  473.                 curRed = CalcNewColorValue(curSourceColor.red, curBlendColor.red, ratio);
  474.                 curGreen = CalcNewColorValue(curSourceColor.green, curBlendColor.green, ratio);
  475.                 curBlue = CalcNewColorValue(curSourceColor.blue, curBlendColor.blue, ratio);
  476.                 // And find the nearest color in our 256 color CLUT
  477.                 newIndex = ColorToIndex(curRed, curGreen, curBlue);
  478.                 // And store it in our table
  479.                 g8BitTranslucencyTable[arrayIndex] = newIndex;
  480.                 arrayIndex++;
  481.             }
  482.         }
  483.     }
  484. }
  485.  
  486.  
  487. // -- CreateCLUTTable --
  488. // This function loads the current CLUT into an array that we use 
  489. // when building our table.
  490. void CreateCLUTTable(void) {
  491.     GWorldPtr     theWorld;
  492.     GDHandle     theDevice;
  493.     short i;
  494.     PixMapHandle thePixMap;
  495.     GetGWorld(&theWorld, &theDevice);
  496.     thePixMap = GetGWorldPixMap(theWorld);
  497.     for (i=0;i<kNumberOfColors;i++) {
  498.         kSystemColorArray[i] = ((*((*thePixMap)->pmTable))->ctTable[i]).rgb;
  499.     }
  500. }
  501.  
  502.  
  503. #pragma mark -----8 Bit Drawing-----
  504. ///--------------------------------------------------------------------------------------
  505. ///--------------------------------------------------------------------------------------
  506. /// 8 Bit drawing
  507. ///--------------------------------------------------------------------------------------
  508. ///--------------------------------------------------------------------------------------
  509.  
  510. ///--------------------------------------------------------------------------------------
  511. //        BlitPixie8BitTranslucentMaskDrawProc
  512. ///--------------------------------------------------------------------------------------
  513. /// Same as BlitPixie8BitMaskDrawProc, only we take a translucent value
  514. /// and pass it to our translucent draw function.
  515. /// (How I miss decent macro facilities).
  516.  
  517. SW_FUNC void BlitPixie8BitTranslucentMaskDrawProc(
  518.     FramePtr srcFrameP,
  519.     FramePtr dstFrameP,
  520.     Rect *srcRect,
  521.     Rect *dstRect) 
  522. {
  523.     Rect dstBlitRect = *dstRect;
  524.     Rect srcBlitRect = *srcRect;
  525.     unsigned long         numBytesPerRow;
  526.     unsigned long         srcBaseOffset;
  527.     unsigned long         translucencyLevel = 0;
  528.     
  529.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  530.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  531.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  532.     SW_ASSERT(srcFrameP->maskPort != NULL);
  533.     SW_ASSERT(g8BitTranslucencyTable != NULL);
  534.  
  535.     if (gSWCurrentSpriteBeingDrawn != NULL)
  536.         translucencyLevel = gSWCurrentSpriteBeingDrawn->translucencyLevel;
  537.  
  538.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  539.     START_32_BIT_MODE
  540.     
  541.         // calculate the offset to the first byte of the source
  542.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - 
  543.         srcFrameP->frameRect.top] + srcBlitRect.left;
  544.  
  545.         // calculate the number of bytes in a row
  546.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
  547.  
  548.     BlitPixieTranslucentMask8Bit(
  549.             // calculate the address of the first byte of the source
  550.         (unsigned long *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  551.  
  552.             // calculate the address of the first byte of the destination
  553.         (unsigned long *)(dstFrameP->frameBaseAddr + 
  554.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
  555.  
  556.             // calculate the address of the first byte of the mask
  557.         (unsigned long *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  558.  
  559.             // calculate the number of rows to blit
  560.         dstBlitRect.bottom - dstBlitRect.top,
  561.  
  562.             // number of bytes in a row 
  563.         numBytesPerRow,
  564.  
  565.         // for PPC, just frameRowBytes
  566.     srcFrameP->frameRowBytes,
  567.     dstFrameP->frameRowBytes,
  568.         //Translucency Level
  569.     translucencyLevel
  570.     );
  571.  
  572.     END_32_BIT_MODE
  573. }
  574.  
  575. ///--------------------------------------------------------------------------------------
  576. //        TranslucencyConvertChar
  577. ///--------------------------------------------------------------------------------------
  578. // Blends a single pixel.
  579.  
  580. unsigned char SWInline TranslucencyConvertChar (
  581.     register unsigned char srcPixel, 
  582.     register unsigned char destPixel, 
  583.     register unsigned long maskPixel,
  584.     register unsigned char *tableAtLevel) {
  585.     
  586.     // If we are to draw it...
  587.     if (! (maskPixel))
  588.         // we need to generate an index of [source pixel][destination pixel] 
  589.         // into our lookup table.  The fastest way is to bitshift the source
  590.         // and OR it.  This generates a sixteen bit number, whose high eight bits
  591.         // are the source pixel and whose low eight bits are the destination pixel.
  592.         return tableAtLevel[(((long)srcPixel << 8) | destPixel)];
  593.     else 
  594.         // otherwise, the mask says not to draw anything.
  595.         return destPixel;
  596. }
  597.  
  598. ///--------------------------------------------------------------------------------------
  599. //        TranslucencyConvertLong
  600. ///--------------------------------------------------------------------------------------
  601. // Blends four 8-bit pixels at a time.  Takes a source and destination long and generates
  602. // a new long representing the four pixels after blending.
  603.  
  604. #if USE_PPC_ASSEMBLY && __MWERKS__ >= 0x1800
  605. // If we are on PPC and CW Pro, we inline some assembly to minimize the number of instructions
  606. // per pixel.  The PPC can rotate, mask and splice the result all in one instruction.
  607. // This speeds this function up by about 10-15%
  608.  
  609. unsigned long SWInline TranslucencyConvertLong (
  610.     register unsigned long srcPixel, 
  611.     register unsigned long destPixel, 
  612.     register unsigned long maskPixel,
  613.     register unsigned char *tableAtLevel) {
  614.  
  615.     register unsigned long curSrc, colorValue;
  616.     // Do the first pixel (bits 24-31)
  617.     // We do this in an analogous way to the way we do a single pixel
  618.     // in TranslucencyConvertChar.  The only difference is that we have
  619.     // to mask off the pixels (using AND) and shift them around different 
  620.     // amounts so we can generate our 16 bit index.
  621.     // N.B. That each of these four operations compiles to a single PPC instruction.
  622.     if (! (maskPixel & 0xFF000000)) {                // is this pixel part of our sprite
  623.         curSrc = ((srcPixel >> 16) & 0x0000FF00);    // shift the source pixel over to be the high byte of our 16 bit index
  624.         __rlwimi(curSrc, destPixel, 8, 24, 31);        // shift the destination pixel over so it's the low byte of our 16 bit index
  625.                                                     // combine them into one index
  626.         colorValue = tableAtLevel[curSrc];            // look up the resulting pixel
  627.         __rlwimi(destPixel, colorValue, 24, 0, 7);    // and shift it back into place as our high end pixel
  628.     } 
  629.     
  630.     // Do the second pixel (bits 16-23) in a similar manner.
  631.     if (! (maskPixel & 0x00FF0000)) {
  632.         curSrc = ((srcPixel >> 8) & 0x0000FF00);
  633.         __rlwimi(    curSrc, destPixel, 16, 24, 31    );
  634.         colorValue = tableAtLevel[curSrc];
  635.         __rlwimi(    destPixel, colorValue, 16, 8, 15    );
  636.     }
  637.     
  638.     // Do the third pixel (bits 8-15) in a similar manner.
  639.     if (! (maskPixel & 0x0000FF00)) {
  640.         curSrc = (srcPixel & 0x0000FF00);
  641.         __rlwimi(    curSrc, destPixel, 24, 24, 31    );
  642.         colorValue = tableAtLevel[curSrc];
  643.         __rlwimi(    destPixel, colorValue, 8, 16, 23    );
  644.     } 
  645.     
  646.     // Do the fourth pixel (bits 0-7) in a similar manner.
  647.     if (! (maskPixel & 0x000000FF)) {
  648.         curSrc = (srcPixel & 0x000000FF) << 8;
  649.         __rlwimi(    curSrc, destPixel, 0, 24, 31    );
  650.         colorValue = tableAtLevel[curSrc];
  651.         __rlwimi(    destPixel, colorValue, 0, 24, 31    );
  652.     }
  653.     
  654.     // return the four pixels we've computed
  655.     return destPixel;    
  656. }
  657.  
  658. #else
  659.  
  660. unsigned long SWInline TranslucencyConvertLong (
  661.     register unsigned long srcPixel, 
  662.     register unsigned long destPixel, 
  663.     register unsigned long maskPixel,
  664.     register unsigned char *tableAtLevel) {
  665.     register unsigned long curSrc, curDest;
  666.     register unsigned long colorValue;
  667.     register unsigned long result = 0L;
  668.     register unsigned long index;
  669.     
  670.     // Do the first pixel (bits 24-31)
  671.     // We do this in an analogous way to the way we do a single pixel
  672.     // in TranslucencyConvertChar.  The only difference is that we have
  673.     // to mask off the pixels (using AND) and shift them around different 
  674.     // amounts so we can generate our 16 bit index.
  675.     if (! (maskPixel & 0xFF000000)) {                // is this pixel part of our sprite
  676.         curSrc = ((srcPixel >> 16) & 0x0000FF00);    // shift the source pixel over to be the high byte of our 16 bit index
  677.         curDest = destPixel >> 24;                    // shift the destination pixel over so it's the low byte of our 16 bit index
  678.         index = curSrc | curDest;                    // combine them into one index
  679.         colorValue = tableAtLevel[index];            // look up the resulting pixel
  680.         result = colorValue << 24;                    // and shift it back into place as our high end pixel
  681.     } else result = (destPixel & 0xFF000000);
  682.     
  683.     // Do the second pixel (bits 16-23) in a similar manner.
  684.     if (! (maskPixel & 0x00FF0000)) {
  685.         curSrc = ((srcPixel >> 8) & 0x0000FF00);
  686.         curDest = (destPixel >> 16) & 0x000000FF;
  687.         index = curSrc | curDest;
  688.         colorValue = tableAtLevel[index];
  689.         result = (colorValue << 16) | result;
  690.     } else result |= (destPixel & 0x00FF0000);
  691.     
  692.     // Do the third pixel (bits 8-15) in a similar manner.
  693.     if (! (maskPixel & 0x0000FF00)) {
  694.         curSrc = (srcPixel & 0x0000FF00);
  695.         curDest = (destPixel >> 8) & 0x000000FF;
  696.         index = curSrc | curDest;
  697.         colorValue = tableAtLevel[index];
  698.         result = (colorValue << 8) | result;
  699.     } else result |= (destPixel & 0x0000FF00);
  700.     
  701.     // Do the fourth pixel (bits 0-7) in a similar manner.
  702.     if (! (maskPixel & 0x000000FF)) {
  703.         curSrc = (srcPixel & 0x000000FF) << 8;
  704.         curDest = (destPixel & 0x000000FF);
  705.         index = curSrc | curDest;
  706.         colorValue = tableAtLevel[index];
  707.         result = colorValue | result;
  708.     } else result = (destPixel & 0x000000FF) | result;
  709.     
  710.     // return the four pixels we've computed
  711.     return result;    
  712. }
  713.  
  714. #endif
  715.  
  716. ///--------------------------------------------------------------------------------------
  717. //        BlitPixieTranslucentMask8Bit
  718. ///--------------------------------------------------------------------------------------
  719. // Modified version of SpriteWorld's standard 8-bit blitter.
  720. // Note that translucencyLevel is preshifted in this case << 16.
  721. // This is so we can OR it with the source and dest pixels in our conversion
  722.  
  723. SW_FUNC void BlitPixieTranslucentMask8Bit(
  724.     register unsigned long * srcPixelP,
  725.     register unsigned long * dstPixelP,
  726.     register unsigned long * maskPixelP,
  727.     register unsigned long rowsToCopy,
  728.     register unsigned long numBytesPerRow,
  729.     register unsigned long srcOffset,
  730.     register unsigned long dstOffset,
  731.     unsigned long translucencyLevel)
  732. {
  733.     register long index;
  734.     register unsigned long * startSrcPixelP;
  735.     register unsigned long * startDstPixelP;
  736.     register unsigned long * startMaskPixelP;
  737.  
  738.     // Since we know the level of translucency, we go to that levels 256x256 table.
  739.     // By doing this here, we only have to do it once.  Now a sixteen bit index
  740.     // we let us find the proper color (i.e. [sourceColorByte][destColorByte])
  741.     register unsigned char *tableAtLevel = &g8BitTranslucencyTable[translucencyLevel];
  742.     
  743.     startSrcPixelP = srcPixelP;
  744.     startDstPixelP = dstPixelP;
  745.     startMaskPixelP = maskPixelP;
  746.     
  747.     while (rowsToCopy--)    
  748.     {
  749.         register fourblits = (numBytesPerRow >> 2);
  750.         
  751.         srcPixelP = startSrcPixelP;
  752.         dstPixelP = startDstPixelP;
  753.         maskPixelP = startMaskPixelP;
  754.         
  755.         for (index = 0; index < fourblits; index++) {
  756.             register unsigned long temp1;
  757.             // For these four pixels, do the lookups to figure out the 
  758.             // pixels that need to be put on the screen.
  759.             temp1 =  TranslucencyConvertLong (srcPixelP[index], 
  760.                                                 dstPixelP[index], 
  761.                                                 maskPixelP[index],
  762.                                                 tableAtLevel);
  763.             // And blit it.
  764.             dstPixelP[index] = temp1;
  765.         }
  766.         srcPixelP += fourblits;
  767.         dstPixelP += fourblits;
  768.         maskPixelP += fourblits;
  769.         
  770.         // If we have any leftover pixels, do them.
  771.         // note we could speed this case up by making a TranslucencyConvertWord
  772.         if (numBytesPerRow & 0x2) {
  773.             register unsigned char temp1;
  774.  
  775.             #ifdef __MWERKS__  // Do it nicely
  776.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++, 
  777.                                                 *((unsigned char *) dstPixelP), 
  778.                                                 *((unsigned char *) maskPixelP)++,
  779.                                                 tableAtLevel);
  780.                 (*((unsigned char *) dstPixelP)++) = temp1;
  781.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++, 
  782.                                                 *((unsigned char *) dstPixelP), 
  783.                                                 *((unsigned char *) maskPixelP)++,
  784.                                                 tableAtLevel);
  785.                 (*((unsigned char *) dstPixelP)++) = temp1;
  786.             #else                 //Do the simplified (and slower) ThinkC way
  787.  
  788.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP), 
  789.                                                 *((unsigned char *) dstPixelP), 
  790.                                                 *((unsigned char *) maskPixelP),
  791.                                                 tableAtLevel);
  792.                 (*((unsigned char *) dstPixelP)) = temp1;
  793.                 
  794.                     // this painfully convoluted syntax is required to make ThinkC 6/7 happy
  795.                 srcPixelP = (unsigned long *)(((char*)srcPixelP) + 1);
  796.                 dstPixelP = (unsigned long *)(((char*)dstPixelP) + 1);
  797.                 maskPixelP = (unsigned long *)(((char*)maskPixelP) + 1);
  798.                 
  799.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP), 
  800.                                                 *((unsigned char *) dstPixelP), 
  801.                                                 *((unsigned char *) maskPixelP),
  802.                                                 tableAtLevel);
  803.                 (*((unsigned char *) dstPixelP)) = temp1;
  804.                 
  805.                 srcPixelP = (unsigned long *)(((char*)srcPixelP) + 1);
  806.                 dstPixelP = (unsigned long *)(((char*)dstPixelP) + 1);
  807.                 maskPixelP = (unsigned long *)(((char*)maskPixelP) + 1);
  808.             #endif
  809.         }
  810.         if (numBytesPerRow & 0x1) {            
  811.             register unsigned char temp1;
  812.             #ifdef __MWERKS__  // Do it nicely
  813.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++, 
  814.                                                 *((unsigned char *) dstPixelP), 
  815.                                                 *((unsigned char *) maskPixelP)++,
  816.                                                 tableAtLevel);
  817.                 (*((unsigned char *) dstPixelP)++) = temp1;
  818.  
  819.             #else                 //Do the simplified (and slower) ThinkC way
  820.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP), 
  821.                                                 *((unsigned char *) dstPixelP), 
  822.                                                 *((unsigned char *) maskPixelP),
  823.                                                 tableAtLevel);
  824.                 (*((unsigned char *) dstPixelP)) = temp1;
  825.                 
  826.                 srcPixelP = (unsigned long *)(((char*)srcPixelP) + 1);
  827.                 dstPixelP = (unsigned long *)(((char*)dstPixelP) + 1);
  828.                 maskPixelP = (unsigned long *)(((char*)maskPixelP) + 1);
  829.             #endif
  830.         }
  831.  
  832.             // bump to next row
  833.         startSrcPixelP = (unsigned long *)(((char*)startSrcPixelP) + srcOffset);
  834.         startDstPixelP = (unsigned long *)(((char*)startDstPixelP) + dstOffset);
  835.         startMaskPixelP = (unsigned long *)(((char*)startMaskPixelP) + srcOffset);
  836.     }
  837. }
  838.  
  839. // A useful helper function
  840. unsigned long Blend8BitPixels (int level, int source, int dest) {
  841.     return g8BitTranslucencyTable[((level << 16) | (source << 8) | dest)];
  842. }
  843.  
  844. ///--------------------------------------------------------------------------------------
  845. ///--------------------------------------------------------------------------------------
  846. ///16 Bit Translucency Blitters
  847. ///--------------------------------------------------------------------------------------
  848. ///--------------------------------------------------------------------------------------
  849.  
  850. #pragma mark -----16 Bit Table Management-----
  851. ///--------------------------------------------------------------------------------------
  852. ///--------------------------------------------------------------------------------------
  853.  
  854. Ptr             gStorageP = NULL;                
  855. unsigned char     *g16BitTranslucencyTable = NULL;
  856.  
  857. OSErr SWCreate16BitTranslucencyTable( void )
  858. {
  859.     register float             alpha,beta,source_multiplied,source_intensity,destination_intensity;
  860.     register long             i;
  861.     register unsigned char     *table_ptr;
  862.     OSErr                    err = noErr;
  863.  
  864.     if (g16BitTranslucencyTable != NULL)
  865.         err = kAlreadyCalledErr;
  866.     
  867.     if (err == noErr)
  868.     {
  869.             // Put the table on a 64k boundary
  870.         gStorageP = NewPtr(32768 + 65536); // 15 bits + 64K Boundary
  871.         if (gStorageP == NULL)
  872.             err = MemError();
  873.     }
  874.     
  875.     
  876.     if (err == noErr)
  877.     {    
  878.         g16BitTranslucencyTable = table_ptr = (unsigned char*)(((long)gStorageP | 0xffff)+1);
  879.         
  880.         /* table lookup offset format: 15 bits
  881.  
  882.              a= alpha
  883.              s= source channel
  884.              d= dest channel
  885.  
  886.             [a][s][d]
  887.             
  888.              offset = aaaaasssssddddd
  889.  
  890.             
  891.              Side note:
  892.              offset=aaaaaXsssssddddd may be kinder on the cache.
  893.         */
  894.         
  895.         for (i=0;i<kNumberOf16BitTranslucencyLevels;i++)
  896.         {
  897.             alpha = ((float)i)/((float)kNumberOf16BitTranslucencyLevels - 1.0);
  898.             beta = 1.0 - alpha;
  899.             for (source_intensity=0;source_intensity<kNumberOf16BitTranslucencyLevels;source_intensity+=1.0)
  900.             {
  901.                 source_multiplied = source_intensity * alpha;
  902.                 
  903.                 for (destination_intensity=0; destination_intensity<kNumberOf16BitTranslucencyLevels; destination_intensity+=1.0)    
  904.                     *table_ptr++ = source_multiplied + (destination_intensity * beta);
  905.             }
  906.         }
  907.     }
  908.     
  909.     return err;
  910. }
  911.  
  912. ///--------------------------------------------------------------------------------------
  913. //  -- SWDispose16BitTranslucencyTable --
  914. ///--------------------------------------------------------------------------------------
  915. // This function must be called to clear the table from memory.
  916.  
  917. void     SWDispose16BitTranslucencyTable(void)
  918. {
  919.         // Only do this if we've created a table.
  920.     if (gStorageP != NULL)
  921.     {
  922.         DisposePtr((Ptr)gStorageP);
  923.         gStorageP = NULL;
  924.         g16BitTranslucencyTable = NULL;
  925.     }
  926. }
  927.  
  928.  
  929. #pragma mark -----16 Bit Blitters-----
  930. ///--------------------------------------------------------------------------------------
  931. //        BlitPixie16BitTranslucentMaskDrawProc
  932. ///--------------------------------------------------------------------------------------
  933.  
  934. SW_FUNC void BlitPixie16BitTranslucentMaskDrawProc (
  935.     FramePtr srcFrameP,
  936.     FramePtr dstFrameP,
  937.     Rect *srcRect,
  938.     Rect *dstRect)
  939. {
  940.     Rect dstBlitRect = *dstRect;
  941.     Rect srcBlitRect = *srcRect;
  942.     unsigned long         srcBaseOffset;
  943.     unsigned long         translucencyLevel = 0;
  944.     unsigned long         height;
  945.     unsigned long         width;
  946.     unsigned long         packedHeightAndWidth;
  947.  
  948.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  949.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  950.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  951.     SW_ASSERT(srcFrameP->maskPort != NULL);
  952.     SW_ASSERT(g16BitTranslucencyTable != NULL);
  953.     
  954.     if (gSWCurrentSpriteBeingDrawn != NULL)
  955.         translucencyLevel = gSWCurrentSpriteBeingDrawn->translucencyLevel;
  956.  
  957.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  958.     START_32_BIT_MODE
  959.     
  960.         // Must be calculated *after* clipping the Sprite!
  961.     height = dstBlitRect.bottom - dstBlitRect.top;
  962.     width  = dstBlitRect.right  - dstBlitRect.left;
  963.     packedHeightAndWidth = ((height & 0x0000FFFF) << 16) | (width & 0x0000FFFF);
  964.  
  965.         // calculate the offset to the first byte of the source
  966.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - 
  967.         srcFrameP->frameRect.top] + 
  968.         (srcBlitRect.left << 1);
  969.  
  970.         // calculate the number of bytes in a row
  971.  
  972.     BlitPixieTranslucencyMask16Bit(
  973.         g16BitTranslucencyTable,
  974.  
  975.             // calculate the address of the first byte of the source
  976.         (short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  977.  
  978.             // calculate the address of the first byte of the destination
  979.         (short *)(dstFrameP->frameBaseAddr + 
  980.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  981.             (dstBlitRect.left << 1)),
  982.  
  983.             // calculate the address of the first byte of the mask
  984.         (short *)(srcFrameP->maskBaseAddr + 
  985.                 srcBaseOffset),
  986.  
  987.             // the number of rows to blit and number of row bytes, packed together
  988.         packedHeightAndWidth,
  989.  
  990.             // for PPC, just frameRowBytes
  991.         srcFrameP->frameRowBytes,
  992.         dstFrameP->frameRowBytes,
  993.         
  994.         translucencyLevel);
  995.  
  996.     END_32_BIT_MODE
  997. }
  998.  
  999.  
  1000. ///--------------------------------------------------------------------------------------
  1001. ///--------------------------------------------------------------------------------------
  1002.  
  1003.  
  1004. #if USE_PPC_ASSEMBLY
  1005.  
  1006. /*
  1007.     16-Bit Masked Translucency Blitter
  1008.  
  1009.     Adapted from Alex Clarke's alphaBlend rect blitter.
  1010.     - Added masking
  1011.     - Adjusted it to deal with sprite world style sources
  1012.     - Packed Height and width so we only have 8 args
  1013.     - Wrote C version so it compiles on 68K.
  1014.  
  1015. */
  1016.  
  1017. // Some defines to make this easier to read
  1018. #define lookup_offset1 alpha
  1019. #define lookup_offset2 r11
  1020. #define lookup_offset3 r12
  1021. #define height r13
  1022. #define width r14
  1023. #define tmp1 r0
  1024. #define tmp2 r31
  1025. #define tmp3 r30
  1026. #define mask_checker tmp3
  1027.  
  1028. void asm BlitPixieTranslucencyMask16Bit (    
  1029.                 register unsigned char *lookup_ptr,
  1030.                 register short *srcPtr,
  1031.                 register short *dstPtr,
  1032.                 register short *maskPtr,
  1033.                 register unsigned long heightAndWidth,
  1034.                 register long srcRowBytes,
  1035.                 register long dstRowBytes,
  1036.                 register long alpha
  1037.                 ) {
  1038.  
  1039.     //store all our temp variables on the stack 
  1040.     stw     tmp2,-4(SP)    
  1041.     stw     tmp3,-8(SP)
  1042.     stw     height,-12(SP)
  1043.     stw     width,-16(SP)
  1044.     stw     lookup_offset2,-20(SP)
  1045.     stw     lookup_offset3,-24(SP)
  1046.  
  1047.     // Pull out the height and width
  1048.     // we pack these two into one because MWerks only allows us to have 8 
  1049.     // function arguments declared as "register".
  1050.     rlwinm   height, heightAndWidth,16, 16, 31
  1051.     rlwinm   width,  heightAndWidth, 0, 16, 31
  1052.  
  1053.     // We need to make the rowBytes be rowBytes - width because we are using
  1054.     // preincrements when getting and setting the pixels
  1055.     add        tmp1, width, width                //adjust for pixels being 2 bytes long
  1056.     sub        srcRowBytes,srcRowBytes,tmp1    //calculateoffsets to the next row
  1057.     sub        dstRowBytes,dstRowBytes,tmp1
  1058.  
  1059.     subi    srcPtr,srcPtr,2    //adjust the pointers so we can use pre-increments
  1060.     subi    maskPtr,maskPtr,2    //adjust the pointers so we can use pre-increments
  1061.     subi    dstPtr,dstPtr,2
  1062.     
  1063.     // Set up the offsets into the blending table for each of our R, G, and B lookups
  1064.     // by setting the high order five bits to the alpha color
  1065.     // Note that these high order bits never get changed as we
  1066.     // work on our pixels, so the alpha (translucency level)
  1067.     // stays the same
  1068.     rlwinm    lookup_offset3,alpha,10,17,21 
  1069.     mr        lookup_offset2,lookup_offset3
  1070.     mr        lookup_offset1,lookup_offset3
  1071.     
  1072. @yloop
  1073.     mtctr     width                                    //set the ctr to so we copy do WIDTH number of pixels
  1074.  
  1075.         @xloop
  1076.             lhzu    tmp1,2(srcPtr)                    //load the source and destination colour
  1077.             lhz     tmp2,2(dstPtr)
  1078.             
  1079.             lhzu     mask_checker, 2(maskPtr)        // load the mask
  1080.             cmpwi    mask_checker, 0                    // if it is not zero
  1081.             bne        @skipBlittingThisPixel            // then keep going
  1082.  
  1083.             rlwimi    lookup_offset3,tmp1,5,22,26        //blue channel source
  1084.             rlwimi    lookup_offset2,tmp1,0,22,26        //green channel source
  1085.             rlwimi    lookup_offset1,tmp1,27,22,26    //red channel source    
  1086.             
  1087.             rlwimi    lookup_offset3,tmp2,0,27,31        //blue channel destination    
  1088.             rlwimi    lookup_offset2,tmp2,27,27,31    //green channel destination
  1089.             rlwimi    lookup_offset1,tmp2,22,27,31    //red channel destination
  1090.             
  1091.             lbzx    tmp3,lookup_ptr,lookup_offset3    //load blended blue channel
  1092.             lbzx    tmp2,lookup_ptr,lookup_offset2    //load blended green channel
  1093.             lbzx    tmp1,lookup_ptr,lookup_offset1    //load blended red channel
  1094.             
  1095.             rlwimi    tmp3,tmp2,5,22,26                //insert green channel into result
  1096.             rlwimi    tmp3,tmp1,10,17,21                //insert red channel into result
  1097.             
  1098.             sthu    tmp3,2(dstPtr)                    //store result
  1099.  
  1100.         @endOfBlitXLoop
  1101.             bdnz    @xloop                            // decrement the ctr and see if we're done                
  1102.     
  1103.     // Now we move the pointers forward to the next row
  1104.     add        srcPtr,srcPtr,srcRowBytes
  1105.     add        dstPtr,dstPtr,dstRowBytes    
  1106.     add        maskPtr,maskPtr,srcRowBytes    
  1107.     
  1108.     //and if we haven't finished, continue
  1109.     subi    height,height,1            
  1110.     cmpwi    height,0
  1111.     bne        @yloop    
  1112.     
  1113.     lwz     tmp2,-4(SP)            //clean up, restore registers we've been using
  1114.     lwz     tmp3,-8(SP)
  1115.     lwz     height,-12(SP)
  1116.     lwz     width,-16(SP)
  1117.     lwz     lookup_offset2,-20(SP)
  1118.     lwz     lookup_offset3,-24(SP)
  1119.  
  1120.  
  1121.     blr
  1122.  
  1123. // Little subroutine to make sure to increment the dstPtr when
  1124. // the mask tells us not to blit 
  1125. @skipBlittingThisPixel
  1126.     addi     dstPtr, dstPtr, 2
  1127.     b         @endOfBlitXLoop
  1128. }
  1129.  
  1130.  
  1131.  
  1132. #undef lookup_offset1
  1133. #undef lookup_offset2
  1134. #undef lookup_offset3
  1135. #undef tmp1
  1136. #undef tmp2
  1137. #undef tmp3
  1138. #undef mask_checker
  1139. #undef width
  1140. #undef height
  1141.  
  1142.  
  1143. #else /* USE_PPC_ASSEMBLY */
  1144.  
  1145. // here is a C version of the above function.  
  1146.  
  1147. void BlitPixieTranslucencyMask16Bit (    
  1148.                 register unsigned char *lookup_ptr,
  1149.                 register short *srcPtr,
  1150.                 register short *dstPtr,
  1151.                 register short *maskPtr,
  1152.                 register unsigned long heightAndWidth,
  1153.                 register long srcRowBytes,
  1154.                 register long dstRowBytes,
  1155.                 register long alpha
  1156.                 ) {
  1157.      register unsigned long height = heightAndWidth >> 16;
  1158.      register unsigned long width = heightAndWidth & 0x0000FFFF;
  1159.      register unsigned long lookup_offset_blue, lookup_offset_green, lookup_offset_red, counter;
  1160.      register unsigned long final_red, final_green, final_result;
  1161.     register short curSource, curDest, curMask;
  1162.  
  1163.     srcRowBytes -= width * 2;
  1164.     dstRowBytes -= width * 2;
  1165.  
  1166.     while (height > 0) {
  1167.         counter = width;
  1168.         while (counter > 0) {
  1169.             lookup_offset_blue = lookup_offset_green = lookup_offset_red = alpha << 10;
  1170.             curSource = *srcPtr++;
  1171.             curMask = *maskPtr++;
  1172.             curDest = *dstPtr;
  1173.             if (curMask == 0) {
  1174.                 lookup_offset_blue |= (curSource << 5) & 0x03E0;
  1175.                 lookup_offset_green |= curSource & 0x03E0;
  1176.                 lookup_offset_red |= (curSource >> 5) & 0x03E0;
  1177.  
  1178.                 lookup_offset_blue |= curDest & 0x001F;
  1179.                 lookup_offset_green |= (curDest >> 5) & 0x001F;
  1180.                 lookup_offset_red |= (curDest >> 10) & 0x001F;
  1181.  
  1182.                 final_red = lookup_ptr[lookup_offset_red];
  1183.                 final_green = lookup_ptr[lookup_offset_green];
  1184.                 final_result = lookup_ptr[lookup_offset_blue];
  1185.  
  1186.                 final_result |= final_green << 5;
  1187.                 final_result |= final_red << 10;
  1188.  
  1189.                 *dstPtr++ = final_result;
  1190.             } else {
  1191.                 dstPtr++;
  1192.             }
  1193.             counter--;
  1194.         }
  1195.  
  1196.         #ifdef MWERKS
  1197.         (char *)srcPtr += srcRowBytes;
  1198.         (char *)maskPtr += srcRowBytes;
  1199.         (char *)dstPtr += dstRowBytes;
  1200.         #else
  1201.         srcPtr = (short *)(((char*)srcPtr) + srcRowBytes);
  1202.         dstPtr = (short *)(((char*)dstPtr) + dstRowBytes);
  1203.         maskPtr = (short *)(((char*)maskPtr) + srcRowBytes);
  1204.         #endif
  1205.  
  1206.         height--;
  1207.     }    
  1208.  
  1209. }
  1210. #endif /* USE_PPC_ASSEMBLY */
  1211.  
  1212.  
  1213. // A useful helper function
  1214. unsigned long Blend16BitPixels (int level, int source, int dest) {
  1215.      register unsigned long lookup_offset_blue, lookup_offset_green, lookup_offset_red;
  1216.      register unsigned long final_red, final_green, final_result;
  1217.  
  1218.     lookup_offset_blue = lookup_offset_green = lookup_offset_red = level << 10;
  1219.     
  1220.     lookup_offset_blue |= (source << 5) & 0x03E0;
  1221.     lookup_offset_green |= source & 0x03E0;
  1222.     lookup_offset_red |= (source >> 5) & 0x03E0;
  1223.  
  1224.     lookup_offset_blue |= dest & 0x001F;
  1225.     lookup_offset_green |= (dest >> 5) & 0x001F;
  1226.     lookup_offset_red |= (dest >> 10) & 0x001F;
  1227.  
  1228.     final_red = g16BitTranslucencyTable[lookup_offset_red];
  1229.     final_green = g16BitTranslucencyTable[lookup_offset_green];
  1230.     final_result = g16BitTranslucencyTable[lookup_offset_blue];
  1231.  
  1232.     final_result |= final_green << 5;
  1233.     final_result |= final_red << 10;
  1234.  
  1235.     return final_result;
  1236. }
  1237.  
  1238.